import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/*
    动态代理的形象例子：图书馆借书
    场景：
    假设我们有一个图书馆的借书系统，图书馆管理员负责给读者办理借书和还书手续。
    管理员还需要在借书时检查读者是否有借书权限（例如是否有逾期未还的书），并在每次操作时记录日志。
    为了不修改现有的图书馆借书逻辑，我们可以使用动态代理来同时实现权限检查和日志记录功能。
 */

/*
    接口：LibraryService 是图书馆的借书和还书接口，定义了图书馆的核心业务功能。
    目标类：LibraryServiceImpl 是具体实现类，负责处理图书馆的借书和还书逻辑。
    动态代理：通过 InvocationHandler 实现动态代理，代理类在调用借书和还书方法之前进行权限检查，并在操作后记录日志。
 */

/*
    动态代理的好处：
    灵活性：动态代理允许我们在不修改目标类（图书馆借书逻辑）的情况下，动态添加功能（权限检查和日志记录）。
    减少重复代码：如果有多个类都需要类似的权限检查和日志记录逻辑，通过动态代理可以避免为每个类编写重复的代理类。
    面向切面编程（AOP）：这种模式类似于面向切面编程（Aspect-Oriented Programming），允许我们将横切关注点（如安全性、日志记录）与核心业务逻辑分离。
 */

public class DynamicProxy {
    public static void main(String[] args) {
        //通过动态代理创建代理对象
        //我们通过 Proxy.newProxyInstance 动态生成代理对象，代理类会拦截对 LibraryService 的方法调用，执行权限检查和日志记录。
        // 创建图书馆的原始服务对象
        LibraryService libraryService = new LibraryServiceImpl();

        // 创建动态代理处理器
        LibraryServiceInvocationHandler handler = new LibraryServiceInvocationHandler(libraryService);

        // 通过 Proxy 动态生成代理对象
        LibraryService proxy = (LibraryService) Proxy.newProxyInstance(
                libraryService.getClass().getClassLoader(),     // 类加载器
                libraryService.getClass().getInterfaces(),      // 接口
                handler);                                       // 处理器

        // 调用代理对象的方法，借书和还书
        proxy.borrowBook("The Great Gatsby");
        proxy.returnBook("The Great Gatsby");
    }
}

// 图书馆借书接口LibraryService，它代表图书馆的借书操作
interface LibraryService {
    void borrowBook(String bookTitle);  // 借书
    void returnBook(String bookTitle);  // 还书
}

// 实现图书馆借书逻辑，LibraryServiceImpl 类实现了 LibraryService 接口，负责真正的借书和还书逻辑。
class LibraryServiceImpl implements LibraryService {
    @Override
    public void borrowBook(String bookTitle) {
        System.out.println("Borrowing the book: " + bookTitle);
    }

    @Override
    public void returnBook(String bookTitle) {
        System.out.println("Returning the book: " + bookTitle);
    }
}


// 创建动态代理处理器
// 我们通过 InvocationHandler 实现动态代理。代理逻辑包括检查权限和记录日志。
class LibraryServiceInvocationHandler implements InvocationHandler {
    private Object target;  // 目标对象（图书馆借书逻辑）

    public LibraryServiceInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 模拟权限检查
        System.out.println("Checking if the user has permission to borrow/return books...");

        // 调用目标方法
        Object result = method.invoke(target, args);

        // 记录日志
        System.out.println("Logging: " + method.getName() + " operation was performed.");

        return result;
    }
}





